/*
 * Copyright (C) 2021 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain an copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

package com.zaaach.citypicker;

import com.zaaach.citypicker.adapter.CityListAdapter;
import com.zaaach.citypicker.adapter.InnerListener;
import com.zaaach.citypicker.adapter.OnPickListener;
import com.zaaach.citypicker.adapter.SearchCityListAdapter;
import com.zaaach.citypicker.db.DBManager;
import com.zaaach.citypicker.model.City;
import com.zaaach.citypicker.model.HotCity;
import com.zaaach.citypicker.model.LocateState;
import com.zaaach.citypicker.model.LocatedCity;
import com.zaaach.citypicker.util.ScreenUtil;
import com.zaaach.citypicker.view.SideIndexBar;
import ohos.agp.animation.Animator;
import ohos.agp.animation.AnimatorValue;

import ohos.agp.components.Component;
import ohos.agp.components.ListContainer;
import ohos.agp.components.Text;
import ohos.agp.components.TextField;
import ohos.agp.components.Image;
import ohos.agp.components.LayoutScatter;
import ohos.agp.utils.TextTool;
import ohos.agp.window.dialog.CommonDialog;
import ohos.app.Context;
import ohos.eventhandler.EventHandler;
import ohos.eventhandler.EventRunner;

import java.util.ArrayList;
import java.util.List;

/**
 * 城市选择控件
 *
 * @since 2021-05-12
 */
public class CityPickerDialog extends CommonDialog implements
        Component.ClickedListener, SideIndexBar.OnIndexTouchedChangedListener, InnerListener, Text.TextObserver {
    private Component mContentView;
    private ListContainer mRecyclerView;
    private ListContainer search;
    private Component mEmptyView;
    private Text mOverlayTextView;
    private SideIndexBar mIndexBar;
    private TextField mSearchBox;
    private Text mCancelBtn;
    private Image mClearAllBtn;

    private CityListAdapter mAdapter;
    private List<City> mAllCities;
    private List<HotCity> mHotCities;
    private List<City> mResults;

    private DBManager dbManager;

    private int height;
    private int width;
    private Context mComtext;
    private boolean isEnableAnim = false;

    private LocatedCity mLocatedCity;
    private int locateState;
    private OnPickListener mOnPickListener;
    private Component parse;
    private EventHandler handler = new EventHandler(EventRunner.getMainEventRunner());

    // 动画起始坐标
    private float startTranslationX = 0;
    private float startTranslationY = 0;
    private float endTranslationX = 0;
    private float endTranslationY = 0;
    private int oldWidth;
    private int oldHeight;
    private final int animatorStar = 1000;
    private final int animatorEnd = 200;
    private Runnable taskRunStart =
            new Runnable() {
                @Override
                public void run() {
                    if (parse != null) {
                        setAnimator(parse);
                    }
                }
            };

    private Runnable taskEnd =
            new Runnable() {
                @Override
                public void run() {
                    if (parse != null) {
                        endTranslationY += parse.getHeight() - oldHeight;
                        parse.createAnimatorProperty()
                                .moveFromY(endTranslationY)
                                .moveToY(startTranslationY)
                                .setDuration(animatorEnd)
                                .setStateChangedListener(
                                        new Animator.StateChangedListener() {
                                            @Override
                                            public void onStart(Animator animator) {
                                            }

                                            @Override
                                            public void onStop(Animator animator) {
                                            }

                                            @Override
                                            public void onCancel(Animator animator) {
                                            }

                                            @Override
                                            public void onEnd(Animator animator) {
                                                hide();
                                                destroy();
                                            }

                                            @Override
                                            public void onPause(Animator animator) {
                                            }

                                            @Override
                                            public void onResume(Animator animator) {
                                            }
                                        })
                                .start();
                    }
                }
            };

    /**
     * CityPickerDialog
     *
     * @param context
     */
    public CityPickerDialog(Context context) {
        super(context);
        this.mComtext = context;
        initData();
        initViews();
        setTransparent(true);
        setSize(ScreenUtil.getScreenPiex(context).width, ScreenUtil.getScreenPiex(context).height);
        setContentCustomComponent(parse);
    }

    private void initViews() {
        parse = LayoutScatter.getInstance(mComtext).parse(ResourceTable.Layout_cp_dialog_city_picker, null, false);
        parse.setTranslationY(0);
        search = (ListContainer) parse.findComponentById(ResourceTable.Id_search);
        mRecyclerView = (ListContainer) parse.findComponentById(ResourceTable.Id_cp_city_recyclerview);
        mAdapter = new CityListAdapter(mAllCities, mHotCities, locateState, mComtext);
        mAdapter.autoLocate(true);
        mAdapter.setInnerListener(this);
        mRecyclerView.setItemProvider(mAdapter);
        mRecyclerView.setScrolledListener(new Component.ScrolledListener() {
            @Override
            public void onContentScrolled(Component component, int i, int i1, int i2, int i3) {
                if (mRecyclerView.getItemPosByVisibleIndex(0) == 0) {
                    mAdapter.refreshLocationItem();
                }
            }
        });
        mEmptyView = parse.findComponentById(ResourceTable.Id_cp_empty_view);
        mOverlayTextView = (Text) parse.findComponentById(ResourceTable.Id_cp_overlay);

        mIndexBar = (SideIndexBar) parse.findComponentById(ResourceTable.Id_cp_side_index_bar);
        mIndexBar.setNavigationBarHeight(ScreenUtil.getStatusBarHeight(mComtext));
        mIndexBar.setOverlayTextView(mOverlayTextView)
                .setOnIndexChangedListener(this);

        mSearchBox = (TextField) parse.findComponentById(ResourceTable.Id_cp_search_box);
        mSearchBox.addTextObserver(this);

        mCancelBtn = (Text) parse.findComponentById(ResourceTable.Id_cp_cancel);
        mClearAllBtn = (Image) parse.findComponentById(ResourceTable.Id_cp_clear_all);
        mCancelBtn.setClickedListener(this);
        mClearAllBtn.setClickedListener(this);
    }

    private void initData() {
        // 初始化热门城市
        if (mHotCities == null || mHotCities.isEmpty()) {
            mHotCities = new ArrayList<>();
            mHotCities.add(new HotCity("北京", "北京", "101010100"));
            mHotCities.add(new HotCity("上海", "上海", "101020100"));
            mHotCities.add(new HotCity("广州", "广东", "101280101"));
            mHotCities.add(new HotCity("深圳", "广东", "101280601"));
            mHotCities.add(new HotCity("天津", "天津", "101030100"));
            mHotCities.add(new HotCity("杭州", "浙江", "101210101"));
            mHotCities.add(new HotCity("南京", "江苏", "101190101"));
            mHotCities.add(new HotCity("成都", "四川", "101270101"));
            mHotCities.add(new HotCity("武汉", "湖北", "101200101"));
        }

        // 初始化定位城市，默认为空时会自动回调定位
        if (mLocatedCity == null) {
            mLocatedCity = new LocatedCity("正在定位…", "未知", "0");
            locateState = LocateState.LOCATING;
        } else {
            locateState = LocateState.SUCCESS;
        }

        dbManager = new DBManager(mComtext);
        mAllCities = dbManager.getData();
        mAllCities.add(0, mLocatedCity);
        mAllCities.add(1, new HotCity("热门城市", "未知", "0"));
        mResults = mAllCities;
    }

    public void setLocatedCity(LocatedCity location) {
        mLocatedCity = location;
    }

    /**
     * 设置热门城市
     *
     * @param data
     */
    public void setHotCities(List<HotCity> data) {
        if (data != null && !data.isEmpty()) {
            this.mHotCities = data;
            mAdapter.updateHotData(mHotCities);
        }
    }

    @Override
    public void onIndexChanged(String index, int position) {
        // 滚动RecyclerView到索引位置
        mAdapter.scrollToSection(index, mRecyclerView);
    }

    /**
     * 修改定位
     *
     * @param location
     * @param state
     */
    public void locationChanged(LocatedCity location, int state) {
        mAdapter.updateLocateState(location, state, mRecyclerView);
    }

    @Override
    protected void onShow() {
        super.onShow();
        if (isEnableAnim) {
            handler.postTask(taskRunStart);
        }
    }

    @Override
    public void dismiss(int position, City data) {
        if (isEnableAnim) {
            handler.postTask(taskEnd);
        } else {
            destroy();
        }
        if (mOnPickListener != null) {
            mOnPickListener.onPick(position, data);
        }
    }

    @Override
    public void locate() {
        if (mOnPickListener != null) {
            mOnPickListener.onLocate();
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (isEnableAnim) {
            handler.removeTask(taskRunStart);
            handler.removeTask(taskEnd);
        }
    }

    public void setOnPickListener(OnPickListener listener) {
        this.mOnPickListener = listener;
    }

    /**
     * 是否开启动画
     *
     * @param isEnable
     */
    public void enableAnimation(boolean isEnable) {
        this.isEnableAnim = isEnable;
    }

    @Override
    public void onClick(Component component) {
        int id = component.getId();
        if (id == ResourceTable.Id_cp_cancel) {
            if (isEnableAnim) {
                handler.postTask(taskEnd);
            } else {
                destroy();
            }
            if (mOnPickListener != null) {
                mOnPickListener.onCancel();
            }
        } else if (id == ResourceTable.Id_cp_clear_all) {
            mSearchBox.setText("");
        }
    }

    @Override
    public void onTextUpdated(String s, int i, int i1, int i2) {
        String keyword = s.toString();
        if (TextTool.isNullOrEmpty(keyword)) {
            mClearAllBtn.setVisibility(Component.HIDE);
            mEmptyView.setVisibility(Component.HIDE);
            mResults = mAllCities;
            search.setVisibility(Component.HIDE);
        } else {
            mClearAllBtn.setVisibility(Component.VISIBLE);

            // 开始数据库查找
            mResults = dbManager.searchCity(keyword);
            if (mResults == null || mResults.isEmpty()) {
                search.setVisibility(Component.HIDE);
                mEmptyView.setVisibility(Component.VISIBLE);
            } else {
                search.setVisibility(Component.VISIBLE);
                mEmptyView.setVisibility(Component.HIDE);
                SearchCityListAdapter searchCityListAdapter =
                        new SearchCityListAdapter(mResults, mHotCities, locateState, mComtext);
                searchCityListAdapter.setInnerListener(this);
                search.setItemProvider(searchCityListAdapter);
            }
        }
        mRecyclerView.scrollTo(0);
    }

    private void setAnimator(final Component targetView) {
        endTranslationY = targetView.getTop();
        targetView.setTranslationY(((Component) targetView.getComponentParent()).getHeight() - targetView.getTop());
        startTranslationY = ((Component) targetView.getComponentParent()).getHeight();
        AnimatorValue animator = new AnimatorValue();
        animator.setDuration(animatorStar);
        animator.setCurveType(Animator.CurveType.ACCELERATE_DECELERATE);
        animator.setValueUpdateListener(
                new AnimatorValue.ValueUpdateListener() {
                    @Override
                    public void onUpdate(AnimatorValue animatorValue, float value) {
                        targetView.setTranslation(
                                (1 - value) * (0 - 0),
                                (1 - value) * (startTranslationY - endTranslationY));
                    }
                });
        animator.setStateChangedListener(
                new Animator.StateChangedListener() {
                    @Override
                    public void onStart(Animator animator) {
                    }

                    @Override
                    public void onStop(Animator animator) {
                    }

                    @Override
                    public void onCancel(Animator animator) {
                    }

                    @Override
                    public void onEnd(Animator animator) {
                        oldHeight = parse.getHeight();
                    }

                    @Override
                    public void onPause(Animator animator) {
                    }

                    @Override
                    public void onResume(Animator animator) {
                    }
                });
        animator.start();
    }
}
